const WebSocket = require('ws');

class Minecraft {

    constructor(McConfig, userInfo) {
        this.userInfo = userInfo[1];
        this._wsUrl = McConfig.wsURL;
        this._wsKey = McConfig.wsKey;
        this._off = false;
    }

    async _delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    async connectWebSocket(target_id, sendMsg) {
        if (this.client) {
            this.client.close();
            delete this.client;
        };

        this.client = new WebSocket(this._wsUrl);
        this.client.on('open', () => {
            console.log("[MC] Ws Connected.");
            this.client.send(JSON.stringify({
                key: this._wsKey
            }))
            this._heartBeatInterval = setInterval(() => {
                this.client.send('ping');
                console.log("[MC] PING!");
            }, 30000);
        });

        this.client.on('message', (data) => {
            this.parse(data.toString(), target_id, sendMsg);
        });

        this.client.on('close', async () => {
            console.log("[MC] Ws Disconnected.");
	        clearInterval(this._heartBeatInterval);
            if (!this._off) {
                await this._delay(1000);
                this.connectWebSocket(target_id, sendMsg);
            }
        });

        this.client.on('error', (err) => {
            console.log("[MC] Ws Error: " + err);
        });
    }

    async tellraw(msg, color, is_bold) {
        return new Promise(async (resolve, reject) => {
            const timeout = setTimeout(() => {
                reject("WsTimeOut");
            },1000);

            while (!this.client || this.client.readyState !== WebSocket.OPEN) {
                console.log("[MC] Ws NOT Ready!");
                await this._delay(100);
            };

            if(timeout) clearTimeout(timeout);

            if (!msg) reject('Null Msg.');
            let arr = this.limitMsgLen(msg);

            let msgArr = arr.map((msgLine, index) => {
                return new Promise(async resolve => {
                    let arrlen = arr.length;
                    let prefix = '';
                    if (index === 0) prefix = '·─ ';
                    else if (index === arrlen - 1) prefix = '└─ ';
                    else {
                        if (msgLine) prefix = '├─ ';
                        else prefix = '│  ';
                    };
                    await this._delay(30 * index);

                    this.client.send(JSON.stringify({
                        command: "tellraw",
                        text: prefix + msgLine,
                        color: color ?? "white",
                        is_bold: is_bold ?? false
                    }));
                    resolve();
                });
            });
            Promise.all(msgArr)
                .then(resolve())
                .catch(err => reject(err));
        });
    }

    async _stopHandler() {
        clearInterval(this._heartBeatInterval);
        delete this.client;
        console.log("[MC] fetchingStopped.");
    }

    async stop() {
        return new Promise((resolve, reject) =>{
            this._off = true;
            const interval = setInterval(() => {
                reject("TimeOut");
            }, 1000);
            this.client.on("close", ()=>{
                this._stopHandler();
                clearInterval(interval);
                resolve()
            })
            this.client.close();
        });
    }

    parse(data, target_id, callback) {
        try {
            data = JSON.parse(data);
        } catch (error) {
            if (error) return;
        };

        if (!data.event) {
            if (data.success) return;
            if (data.error) {
                console.log("[MC] wsMsg Recieved Err: " + data.error);
                return;
            }
            if (!data.username || !data.message) {
                data.username = "MC侦测器";
                data.message = "未知DATA: " + JSON.stringify(data);
            };
            callback(this.getFormatMsg(data), target_id);
            return;
        };

        let content = '';
        switch (data.event) {
            case "leave":
                content = "😭Man What can I say? **";
                if (this.userInfo[data.username])
                    content += `(font)${data.username}(font)[${this.userInfo[data.username].color}]`;
                else content += data.username ?? "somebody";
                content += "** OUT!  😭";
                break;
            case "join":
                content = "😎Man What can I say? **";
                if (this.userInfo[data.username])
                    content += `(font)${data.username}(font)[${this.userInfo[data.username].color}]`;
                else content += data.username ?? "somebody";
                content += "** BACK! 😎";
                break;
            default:
                content = "MC侦测器: 未知Event: " + data.event;
                break;
        };

        callback(JSON.stringify([{
            type: "card",
            color: "#b7def4",
            size: "lg",
            modules: [
                {
                    type: "section",
                    text: {
                        type: "kmarkdown",
                        content,
                    }
                }
            ]
        }]), target_id);
    }

    limitMsgLen(msg){
        return msg.split('\n')
            .map(item => {
                return (item.length > 60) ? item.match(/.{1,60}/g) : item
            } )
            .flat();
      }
      

    getFormatMsg(data) {
        let user = data.username;
        let msg = data.message;
        let color, title, colorRGB = null;
        if (this.userInfo[user]) {
            colorRGB = this.userInfo[user].colorRGB ?? "#b7def4";
            color = this.userInfo[user].color ?? null;
            title = this.userInfo[user].title ?? null;
        };

        let content = '';
        if (title) content += `(font)[${title}](font)[${color}]\t`;
        if (color) content += `(font)${user}(font)[${color}]: ${msg}`;
        else content += `${user}: ${msg}`;
        return JSON.stringify([{
            type: "card",
            color: colorRGB,
            size: "lg",
            modules: [
                {
                    type: "section",
                    text: {
                        type: "kmarkdown",
                        content
                    }
                }
            ]
        }]);
    }
};

module.exports = Minecraft;


// let is_new = false;

// for (let i = dataArr.length - 1; i >= 0; i--){
//     if(is_new) {
//         callback(this.getFormatMsg(dataArr[i]), target_id);
//         await this._delay(this.send_delay);
//     };
//     if(dataArr[i].id === this.latestID){
//         this.latestID = dataArr[0].id;
//         is_new = true;
//         //     };
//     if (i === 0) {
//         this.latestID = dataArr[0].id;
//         if (!is_new){
//             for (let j = dataArr.length - 1; j >= 0; j--) {
//                 callback(this.getFormatMsg(dataArr[j]), target_id);
//                 await this._delay(this.send_delay);
//             };
//         };
//     };
// };
